package com.elysium.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.elysium.constants.Constants;
import com.elysium.constants.GlobalExceptionCode;
import com.elysium.exception.GlobalException;
import com.elysium.feign.AppLoginFeignClient;
import com.elysium.mapper.DriverAuthMaterialMapper;
import com.elysium.mapper.DriverMapper;
import com.elysium.pojo.domain.*;
import com.elysium.pojo.dto.DriverSummaryDto;
import com.elysium.pojo.dto.LocationChangeDto;
import com.elysium.pojo.param.RegisterSaveLoginParam;
import com.elysium.pojo.properties.DriverSettingProperties;
import com.elysium.result.R;
import com.elysium.service.IDriverService;
import com.elysium.service.IDriverSettingService;
import com.elysium.service.IDriverSummaryService;
import com.elysium.service.IDriverWalletService;
import com.elysium.template.AppWeChatTemplate;
import com.elysium.utils.AssertUtil;
import com.elysium.utils.BitStatesUtil;
import com.elysium.utils.NameUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.tags.form.FormTag;

import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.TimeUnit;


/**
 * <p>
 * 司机对象 服务实现类
 * </p>
 *
 * @author Neuronet
 * @since 2024-07-27
 */
@Service
public class DriverServiceImpl extends ServiceImpl<DriverMapper, Driver> implements IDriverService {

    @Autowired
    private IDriverWalletService driverWalletService;

    @Autowired
    private IDriverSettingService driverSettingService;

    @Autowired
    private IDriverSummaryService driverSummaryService;

    @Autowired
    private DriverSettingProperties driverSettingProperties;

    @Autowired
    private AppWeChatTemplate appWeChatTemplate;

    @Autowired
    private AppLoginFeignClient appLoginFeignClient;

    @Autowired
    private DriverAuthMaterialMapper driverAuthMaterialMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 司机上线处理
     */
    @Override
    public void onLine() {
        // 业务校验 1.查询司机的配置信息，判断是否存在
        long loginId = StpUtil.getLoginIdAsLong();
        DriverSetting driverSetting = driverSettingService.getById(loginId);
        AssertUtil.isNotNull(driverSetting, GlobalExceptionCode.SERVICE_ERROR);
        // 业务实现 1.把司机的配置信息存储到Redis中
        String key = String.format(Constants.Redis.DRIVER_ONLINE_KEY, loginId);
        // @TODO:上线之前把过期时间修改为30分钟
        redisTemplate.opsForValue().set(key, driverSetting, 10, TimeUnit.HOURS);
    }

    /**
     * 司机下线处理
     */
    @Override
    public void offLine() {
        // 1.删除司机的Redis配置
        String loginId = StpUtil.getLoginIdAsString();
        String key = String.format(Constants.Redis.DRIVER_ONLINE_KEY, loginId);
        redisTemplate.delete(key);
        // 2.删除司机的GEO位置信息
        redisTemplate.opsForGeo().remove(Constants.Redis.DRIVER_LOCATION_KEY, loginId);
    }

    /**
     * 监听司机的位置，保存经纬度到GEO
     */
    @Override
    public void changLocationToGeo(LocationChangeDto locationChangeDto) {
        String loginId = StpUtil.getLoginIdAsString();
        String key = String.format(Constants.Redis.DRIVER_ONLINE_KEY, loginId);
        Object driverSetting = redisTemplate.opsForValue().get(key);
        if (ObjectUtil.isNull(driverSetting)) {
            return;
        }
        redisTemplate.opsForGeo().add(
                Constants.Redis.DRIVER_LOCATION_KEY,
                new Point(locationChangeDto.getLongitude(), locationChangeDto.getLatitude()),
                StpUtil.getLoginIdAsString()
        );
    }

    /**
     * 小程序司机注册
     * @param openIdCode
     * Vo:后端返回给前端展示的临时对象
     * Dto：后端之间传递参数所使用的临时对象，也用于接收前端参数的临时对象
     */
    @Override
    @Transactional
    public void register(String openIdCode) {
        // 获取openId
        String openId = appWeChatTemplate.getOpenIdByCode(openIdCode);

        // 获取电话号
//        String phone = appWeChatTemplate.getPhoneByAccessTokenAndCode(phoneCode);

        // 创建 QueryWrapper 查询条件，查找数据库中是否已有该 openId 的用户（司机）
        // QueryWrapper<Driver> driverQueryWrapper = new QueryWrapper<>();
        // driverQueryWrapper.eq("open_id", openId);

        // 通过 openId 从数据库中查询用户（司机）信息（上述两行代码的简写）
        Driver driver = super.getOne(new QueryWrapper<Driver>().eq("open_id", openId));

        // 如果通过 openId 查询到对应的用户，抛出用户已存在异常
        AssertUtil.isNull(driver, GlobalExceptionCode.PARAM_PHONE_EXIST);
//        if (ObjectUtil.isNotNull(driver)){
//            throw new GlobalException(GlobalExceptionCode.PARAM_PHONE_EXIST);
//        }

        // 3.业务实现
        // 3.1.保存Driver信息
        driver = new Driver();
        saveDriver(driver, openId);
        Long id = driver.getId();
        String password = "123456";
        String hashpw = BCrypt.hashpw(password, BCrypt.gensalt());
        // 3.2.初始化从表：钱包、配置、统计
        initDriverAssociation(id, hashpw);

        // 3.3.调用feign接口保存Login
        saveLogin(id, openId, hashpw, Constants.Login.TYPE_DRIVER);

    }

    /**
     * 查询司机实名认证信息
     * @return
     */
    @Override
    public DriverAuthMaterial getrealAuthInfo() {
        // 1.查询司机实名认证信息
        DriverAuthMaterial driverAuthMaterial = driverAuthMaterialMapper.selectOne(new LambdaQueryWrapper<DriverAuthMaterial>()
                .eq(DriverAuthMaterial::getDriverId, StpUtil.getLoginIdAsLong())
                .orderByDesc(DriverAuthMaterial::getCreateTime)
                .last("limit 1"));
        return driverAuthMaterial;
    }

    /**
     * 获取司机今日接单数据
     * @return
     */

    @Override
    public DriverSummaryDto getDriverSummary() {
        DriverSummary driverSummary = driverSummaryService.getById(StpUtil.getLoginIdAsLong());
        AssertUtil.isNotNull(driverSummary, GlobalExceptionCode.SERVICE_ERROR);
        return BeanUtil.copyProperties(driverSummary, DriverSummaryDto.class);
    }

    private void saveLogin(Long id, String openId, String password, Integer type) {
        String phone = "19713258175";
        RegisterSaveLoginParam registerSaveLoginParam = new RegisterSaveLoginParam();
        registerSaveLoginParam.setUsername(phone);
        registerSaveLoginParam.setPassword(password);
        registerSaveLoginParam.setType(type);
        registerSaveLoginParam.setEnabled(true);
        registerSaveLoginParam.setAvatar(Constants.DEFAULT_AVATAR);
        registerSaveLoginParam.setAdmin(false);
        String name = NameUtil.getName();
        registerSaveLoginParam.setNickName(name);
        registerSaveLoginParam.setOpenId(openId);
        registerSaveLoginParam.setName(name);
        registerSaveLoginParam.setPhone(phone);
        registerSaveLoginParam.setId(id);

        R<Void> r = appLoginFeignClient.save(registerSaveLoginParam);
        if (!r.isSuccess()){
            throw new GlobalException(GlobalExceptionCode.SERVICE_ERROR);
        }
    }

    /**
     * 初始化司机关联表
     * @param id
     */
    private void initDriverAssociation(Long id, String password) {
        DriverWallet driverWallet = new DriverWallet();
        driverWallet.setId(id);
        driverWallet.setAmount(new BigDecimal("0"));
        // 最好的处理：随机生成密码，并且发送短信验证码告知用户，这个作为你们1号的自研,自研阿里云短信
        driverWallet.setPassword(password);
        driverWallet.setDeleted(false);
        driverWallet.setVersion(0);
        driverWallet.setCreateTime(new Date());
        driverWalletService.save(driverWallet);

        DriverSetting driverSetting = new DriverSetting();
        driverSetting.setId(id);
        driverSetting.setAutoAccept(false);
        driverSetting.setOrientation(false);
        driverSetting.setListenService(false);
        driverSetting.setOrderDistance(driverSettingProperties.getOrderDistance());
        driverSetting.setRangeDistance(driverSettingProperties.getRangeDistance());
        driverSetting.setCreateTime(new Date());
        driverSetting.setDeleted(false);
        driverSetting.setVersion(0);
        driverSettingService.save(driverSetting);


        DriverSummary driverSummary = new DriverSummary();
        driverSummary.setId(id);
        driverSummary.setLevel(0);
        driverSummary.setTotalOrders(0);
        driverSummary.setWeekOrders(0);
        driverSummary.setGoodComments(0);
        driverSummary.setAppeal(0);
        driverSummary.setTotalComplaint(0);
        driverSummary.setTodayTotalCancel(0);
        driverSummary.setDriveDuration(0);
        driverSummary.setTradeOrders(0);
        driverSummary.setTodayTradeOrders(0);
        driverSummary.setTodayComplaint(0);
        driverSummary.setTodayCancel(0);
        driverSummary.setTodayIncome(new BigDecimal("0"));
        driverSummary.setCreateTime(new Date());
        driverSummary.setDeleted(false);
        driverSummary.setVersion(0);
        driverSummaryService.save(driverSummary);


    }

    /**
     * 保存司机对象
     * @param driver
     */
    private void saveDriver(Driver driver, String openId) {
        // driver.setPhone("");
        driver.setArchive(false);
        driver.setCreateTime(new Date());
        driver.setDeleted(false);
        driver.setVersion(0);
        driver.setOpenId(openId);
         driver.setBitState(BitStatesUtil.OP_PHONE);
        super.save(driver);
    }
}
